#ifndef MEMORY_MANAGER_H
#define MEMORY_MANAGER_H

#include <Types.h>
#include <List.h>
#include <PageTable.h>
#include <DataSource.h>


#define MA_WRITE	(1 << 0)
#define MA_EXEC		(1 << 1) 
#define MA_PRIVATE	(1 << 5)

#define PROC_SIZE	(0xc0000000 - 1)

extern void pageFoultInterrapt();

class MemoryArea{
	addr_t		_begin;		//Начало области
	addr_t		_end;		//Адрес следующий за последним в области
	uint32		_prot;
	uint32		_flags;
	DataSource*	_src;
	public:
	Link		areas;		//Список областей принадлежащих процессу
		MemoryArea(addr_t, size_t, uint32, uint32, DataSource *);
		MemoryArea(const MemoryArea &);
		
		inline uint32 getProt(){return _prot;}
		inline void setProt(uint32 prot){_prot = prot;}
		inline addr_t getBegin();
		inline void setBegin(addr_t);
		inline addr_t getEnd();
		inline void setEnd(addr_t);
		inline DataSource *getDataSource(){return _src;}
};

inline addr_t MemoryArea::getBegin(){
	return _begin;
}

inline void MemoryArea::setBegin(addr_t begin){
	_begin = begin;
}

inline addr_t MemoryArea::getEnd(){
	return _end;
}

inline void MemoryArea::setEnd(addr_t end){
	_end = end;
}

class MemoryManager{
	PageTable*	_gpd;				//Указатель на главный каталог страниц
	MemoryArea*	_last_area;			//Последняя сработавшая область
	addr_t		_search_start_addr;	//Адрес, с которого нужно начинать поиск свободной области
	
	addr_t		_code_start;	//Адрес начала кода
	addr_t		_code_end;	
	addr_t		_data_start;
	addr_t		_data_end;
	addr_t		_bss_start;
	addr_t		_bss_end;
	addr_t		_stack_start;
	public:
	List	mas;		//Список областей памяти процесса
		MemoryManager();
		MemoryManager(const MemoryManager &);
		MemoryManager(MemoryManager *form_mm, uint32 flag);
		inline MemoryArea * getInUse();
		inline void setInUse(MemoryArea *ma);
		inline addr_t getFreeAddr();
		inline void setFreeAddr(addr_t addr);
		inline addr_t getCodeStart(){return _code_start;}
		inline void setCodeStart(addr_t cs){_code_start = cs;}
		inline addr_t getCodeEnd(){return _code_end;}
		inline void setCodeEnd(addr_t ce){_code_end = ce;}
		inline addr_t getDataStart(){return _data_start;}
		inline void setDataStart(addr_t ds){_data_start = ds;}
		inline addr_t getDataEnd(){return _data_end;}
		inline void setDataEnd(addr_t de){_data_end = de;}
		inline addr_t getBssStart(){return _bss_start;}
		inline void setBssStart(addr_t bs){_bss_start = bs;}
		inline addr_t getBssEnd(){return _bss_end;}
		inline void setBssEnd(addr_t be){_bss_end = be;}
		inline addr_t getStackStart(){return _stack_start;}
		inline void setStackStart(addr_t ss){_stack_start = ss;}
		
		
		MemoryArea * createArea(addr_t begin, uint32 size, uint32 prot, uint32 flags, DataSource *ds, MemoryArea *after = NULL);
		MemoryArea * findArea(addr_t addr);
		addr_t findFreeBlock(addr_t start, size_t sz);
		MemoryArea * memoryMap(void *addr, size_t len, int prot, int flags, DataSource *ds, int32 offset = -1);
		uint32 memoryUnMap(void *addr, size_t len);
		void printMap();
		
		PageTable * getGPD(){return _gpd;}
		uint32 pageFoult(addr_t addr, uint32 flags);
		
};

inline MemoryArea * MemoryManager::getInUse(){
	return _last_area;
}

inline void MemoryManager::setInUse(MemoryArea *ma){
	_last_area = ma;
}

inline addr_t MemoryManager::getFreeAddr(){
	return _search_start_addr;
}

inline void MemoryManager::setFreeAddr(addr_t addr){
	_search_start_addr = addr;
}

#endif /* MEMORY_MANAGER_H */

